﻿using DDNS.Cache;
using DDNS.Infrastructure;
using DDNS.Model.Config;
using DDNS.Model.DTO;
using DDNS.Model.Entities;
using DDNS.Model.Enum;
using DDNS.Model.Results;
using DDNS_IPv4_IPv6.Interface;
using Newtonsoft.Json;
using Refit;
using System.Text;

namespace DDNS_IPv4_IPv6.Service
{
    public class DynamicParsingService : IDynamicParsingService
    {
        /// <summary>
        /// 缓存配置
        /// </summary>
        private CachesConfig _cacheConfig;
        /// <summary>
        /// DNSPod配置
        /// </summary>
        private TencentDNSPodConfig _DNSPodConfig;
        /// <summary>
        /// 获取IP地址URL配置
        /// </summary>
        private GetIPUrlConfig _getIPUrlConfig;
        /// <summary>
        /// 定义Refit访问的域名信息
        /// </summary>
        private IDnsPod _DNSPodInterface;

        private readonly ILogger<DynamicParsingService> _log4Net;

        public DynamicParsingService(ILogger<DynamicParsingService> log4Net)
        {
            _cacheConfig = PassportConfig.Get<CachesConfig>("Caches") ?? throw new ArgumentNullException("Caches config is null");
            _DNSPodConfig = PassportConfig.Get<TencentDNSPodConfig>("TencentDNSPod") ?? throw new ArgumentNullException("TencentDNSPod config is null");
            _getIPUrlConfig = PassportConfig.Get<GetIPUrlConfig>("GetIPUrl") ?? throw new ArgumentNullException("GetIPUrl config is null");
            _DNSPodInterface = RestService.For<IDnsPod>(_DNSPodConfig.RequestUrl);
            _log4Net = log4Net;
        }

        /// <summary>
        /// 获取IPv4-动态更新DNS
        /// </summary>
        /// <returns></returns>
        public async Task<string> SetDDNS_IPv4()
        {
            string ret = string.Empty;
            try
            {
                var domainList = CacheHelper.GetCache<List<DomainName>>(_cacheConfig.DomainKey);
                var isUpdate = CacheHelper.GetCache<string>(_cacheConfig.IsUpdateIPv4Key);//是否更新了IPv4域名列表
                var record_ip = CacheHelper.GetCache<string>(_cacheConfig.IPv4Key) ?? "1.0.0.1";
                if (domainList == null || string.IsNullOrEmpty(isUpdate)) return ret;
                domainList = domainList.Where(m => m.Type == DDNS.Model.Enum.EnumDomainType.IPv4 || m.Type == DDNS.Model.Enum.EnumDomainType.ALL).ToList();
                if (!domainList.Any()) return ret;
                string IPv4 = Tools.GetIP(_getIPUrlConfig.GetIPv4Url, Encoding.UTF8, EnumIPType.IPv4);
                //1、手动添加域名之后需要进入进行解析
                //2、IP变化之后需要进入进行解析
                if (string.IsNullOrEmpty(IPv4)) return ret;
                if (isUpdate.ToLower() == "true" || record_ip != IPv4)
                {
                    CacheHelper.SetCache<string>(_cacheConfig.IsUpdateIPv4Key, "false", DateTime.Now.AddYears(1));//更新列表标记
                    List<DomainName> templist = new List<DomainName>();
                    foreach (var item in domainList)
                    {
                        var recordModel = GetRecordList(item, EnumDomainType.IPv4).Result;
                        if (recordModel == null || recordModel?.status.code != "1")
                        {
                            ret += "\n" + $"子域名(IPv4)[{item.Domain}]获取域名信息异常：{recordModel?.status.message}";
                            _log4Net.LogError($"子域名(IPv4)[{item.Domain}]获取域名信息异常：{recordModel?.status.message}");
                            templist.Add(item);
                            continue;
                        }//获取需要解析的域名记录

                        var dns_ip = recordModel.records?[0].value;
                        if (dns_ip == IPv4)
                        {
                            ret += "\n" + $"子域名(IPv4)[{item.Domain}]获取域名解析记录成功，但未动态更新DNS，因目前的IPv4地址与线上解析一致";
                            _log4Net.LogWarning($"子域名(IPv4)[{item.Domain}]获取域名解析记录成功，但未动态更新DNS，因目前的IPv4地址与线上解析一致");
                            continue;
                        }//判断当前解析的值是否与将要解析的值一致

                        string domain_record = item.Domain.Replace(recordModel.domain.name, "");
                        domain_record = domain_record.Substring(0, domain_record.Length - 1);
                        var updateModel = ModifyRecord(recordModel, IPv4, domain_record, EnumDomainType.IPv4).Result;
                        if (updateModel == null || updateModel?.status.code != "1")
                        {
                            ret += "\n" + $"更新动态DNS异常：{updateModel?.status.message}";
                            _log4Net.LogError($"更新动态DNS异常：{updateModel?.status.message}");
                            continue;
                        }
                        ret += "\n" + $"子域名(IPv4)[{item.Domain}]修改记录成功，原IP值为：{recordModel.records?[0].value}，新IP为：{IPv4}";
                        _log4Net.LogInformation($"子域名(IPv4)[{item.Domain}]修改记录成功，原IP值为：{recordModel.records?[0].value}，新IP为：{IPv4}");
                    }
                    if (templist.Count > 0)
                    {
                        List<DomainName> tempdomainlist = new List<DomainName>();
                        domainList = CacheHelper.GetCache<List<DomainName>>(_cacheConfig.DomainKey);
                        foreach (var domain in domainList)
                        {
                            foreach (var item in templist)
                            {
                                if (domain.Domain == item.Domain)
                                {
                                    var recordModel = GetRecordList(item, EnumDomainType.IPv6).Result;
                                    if (recordModel == null || recordModel?.status.code != "1")
                                    {
                                        tempdomainlist.Add(item);
                                    }//去掉这个域名
                                    else
                                    {
                                        domain.Type = EnumDomainType.IPv6;
                                    }//修改域名类型
                                }
                            }
                        }
                        domainList = domainList.Where(m => !tempdomainlist.Select(g => g.Domain).Contains(m.Domain)).ToList();
                        CacheHelper.SetCache(_cacheConfig.DomainKey, domainList, DateTime.Now.AddYears(1));//缓存需要动态解析的域名
                    }//去掉或者更新不符合的域名
                    CacheHelper.SetCache<string>(_cacheConfig.IPv4Key, IPv4);//缓存好IPv4地址
                }
            }
            catch (Exception ex)
            {
                ret = "\n" + $"获取IPv4且动态更新DNS错误:{ex.Message}";
                _log4Net.LogError($"获取IPv4且动态更新DNS错误:{ex.Message}");
            }
            return ret;
        }

        /// <summary>
        /// 获取IPv6-动态更新DNS
        /// </summary>
        /// <returns></returns>
        public async Task<string> SetDDNS_IPv6()
        {
            string ret = string.Empty;
            try
            {
                var domainList = CacheHelper.GetCache<List<DomainName>>(_cacheConfig.DomainKey);
                var isUpdate = CacheHelper.GetCache<string>(_cacheConfig.IsUpdateIPv6Key);//是否更新了IPv6域名列表
                var record_ip = CacheHelper.GetCache<string>(_cacheConfig.IPv6Key) ?? "0:0:0:0:0:0:0:1";
                if (domainList == null || string.IsNullOrEmpty(isUpdate)) return ret;
                domainList = domainList.Where(m => m.Type == DDNS.Model.Enum.EnumDomainType.IPv6 || m.Type == DDNS.Model.Enum.EnumDomainType.ALL).ToList();
                if (!domainList.Any()) return ret;
                string IPv6 = Tools.GetIP(_getIPUrlConfig.GetIPv6Url, Encoding.UTF8, EnumIPType.IPv6);
                //1、手动添加域名之后需要进入进行解析
                //2、IP变化之后需要进入进行解析
                if (string.IsNullOrEmpty(IPv6)) return ret;
                if (isUpdate.ToLower() == "true" || record_ip != IPv6)
                {
                    CacheHelper.SetCache<string>(_cacheConfig.IsUpdateIPv6Key, "false", DateTime.Now.AddYears(1));//更新列表标记
                    List<DomainName> templist = new List<DomainName>();
                    foreach (var item in domainList)
                    {
                        var recordModel = GetRecordList(item, EnumDomainType.IPv6).Result;
                        if (recordModel == null || recordModel?.status.code != "1")
                        {
                            ret += "\n" + $"子域名(IPv6)[{item.Domain}]获取域名信息异常：{recordModel?.status.message}";
                            _log4Net.LogError($"子域名(IPv6)[{item.Domain}]获取域名信息异常：{recordModel?.status.message}");
                            templist.Add(item);
                            continue;
                        }

                        var dns_ip = recordModel.records?[0].value;
                        if (dns_ip == IPv6)
                        {
                            ret += "\n" + $"子域名(IPv6)[{item.Domain}]获取域名解析记录成功，但未动态更新DNS，因目前的IPv6地址与线上解析一致";
                            _log4Net.LogWarning($"子域名(IPv6)[{item.Domain}]获取域名解析记录成功，但未动态更新DNS，因目前的IPv6地址与线上解析一致");
                            continue;
                        }//判断当前解析的值是否与将要解析的值一致

                        string domain_record = item.Domain.Replace(recordModel.domain.name, "");
                        domain_record = domain_record.Substring(0, domain_record.Length - 1);
                        var updateModel = ModifyRecord(recordModel, IPv6, domain_record, EnumDomainType.IPv6).Result;
                        if (updateModel == null || updateModel?.status.code != "1")
                        {
                            ret += "\n" + $"更新动态DNS异常：{updateModel?.status.message}";
                            _log4Net.LogError($"更新动态DNS异常：{updateModel?.status.message}");
                            continue;
                        }
                        ret += "\n" + $"子域名(IPv6)[{item.Domain}]修改记录成功，原IP值为：{recordModel.records?[0].value}，新IP为：{IPv6}";
                        _log4Net.LogInformation($"子域名(IPv6)[{item.Domain}]修改记录成功，原IP值为：{recordModel.records?[0].value}，新IP为：{IPv6}");
                    }
                    if (templist.Count > 0)
                    {
                        List<DomainName> tempdomainlist = new List<DomainName>();
                        domainList = CacheHelper.GetCache<List<DomainName>>(_cacheConfig.DomainKey);//再获取一次避免
                        foreach (var domain in domainList)
                        {
                            foreach (var item in templist)
                            {
                                if (domain.Domain == item.Domain)
                                {
                                    var recordModel = GetRecordList(item, EnumDomainType.IPv6).Result;
                                    if (recordModel == null || recordModel?.status.code != "1")
                                    {
                                        tempdomainlist.Add(item);
                                    }//去掉这个域名
                                    else
                                    {
                                        domain.Type = EnumDomainType.IPv4;
                                    }//修改域名类型
                                }
                            }
                        }
                        domainList = domainList.Where(m => !tempdomainlist.Select(g => g.Domain).Contains(m.Domain)).ToList();
                        CacheHelper.SetCache(_cacheConfig.DomainKey, domainList, DateTime.Now.AddYears(1));//缓存需要动态解析的域名
                    }//去掉或者更新不符合的域名
                    CacheHelper.SetCache<string>(_cacheConfig.IPv6Key, IPv6);//缓存好IPv6地址
                }
            }
            catch (Exception ex)
            {
                ret = "\n" + $"获取IPv6且动态更新DNS错误:{ex.Message}";
                _log4Net.LogError($"获取IPv6且动态更新DNS错误:{ex.Message}");
            }
            return ret;
        }

        /// <summary>
        /// 获取子域名记录
        /// </summary>
        /// <param name="recDto"></param>
        /// <returns></returns>
        public async Task<RecordListResult> GetRecordList(DomainName item, EnumDomainType type)
        {
            var ret = new RecordListResult();
            try
            {
                //分解域名
                int p1 = item.Domain.LastIndexOf(".");                 //最后一次“.”出现的位置                
                int p2 = item.Domain.Substring(0, p1).LastIndexOf(".");//倒数第二个“.”出现的位置                
                string domain_root = item.Domain.Substring(p2 + 1);//根域名
                string domain_record = item.Domain.Substring(0, p2);//二级域名记录值
                RecordDTO recDto = new RecordDTO()
                {
                    login_token = _DNSPodConfig.ID.ToString() + "," + _DNSPodConfig.Token,
                    format = "json",
                    lang = "cn",
                    error_on_empty = "yes",
                    record_type = (type == EnumDomainType.IPv4 ? "A" : "AAAA"),
                    domain = domain_root,
                    sub_domain = domain_record
                };//获取记录列表参数
                var recordStr = await _DNSPodInterface.RecordList(recDto);
                if (string.IsNullOrEmpty(recordStr)) return ret;
                ret = JsonConvert.DeserializeObject<RecordListResult>(recordStr);
            }
            catch (Exception ex)
            {
                string message = ex.Message;
            }
            return ret;
        }

        /// <summary>
        /// 调整记录（实现动态域名解析）
        /// </summary>
        public async Task<DomainRecordResults> ModifyRecord(RecordListResult recordModel, string IP, string domain_record, EnumDomainType type)
        {
            var ret = new DomainRecordResults();
            try
            {
                int domainId = 0;//域名ID值
                int recordId = 0;//记录ID值
                int _mx = 0;//优先级
                int _ttl = 600;//TTL(腾讯云最低值为600，即10分钟)
                DomainRecordDTO dto = new DomainRecordDTO()
                {
                    login_token = _DNSPodConfig.ID.ToString() + "," + _DNSPodConfig.Token,
                    format = "json",
                    lang = "cn",
                    error_on_empty = "yes",
                    domain_id = int.TryParse(recordModel.domain?.id, out domainId) == false ? 0 : domainId,
                    record_id = int.TryParse(recordModel.records?[0].id, out recordId) == false ? 0 : recordId,
                    sub_domain = domain_record,
                    record_type = recordModel.records?[0].type ?? (type == EnumDomainType.IPv4 ? "A" : "AAAA"),
                    record_line = recordModel.records?[0].line ?? "默认",
                    record_line_id = recordModel.records?[0].line_id,
                    value = IP,
                    mx = int.TryParse(recordModel.records?[0].mx, out _mx) == false ? 0 : _mx,
                    ttl = int.TryParse(recordModel.records?[0].ttl, out _ttl) == false ? 0 : _ttl,
                    status = recordModel.records?[0].status,
                };//更新动态DNS记录入参
                var updateStr = await _DNSPodInterface.UpdateDDNS(dto);
                if (string.IsNullOrEmpty(updateStr)) return ret;
                ret = JsonConvert.DeserializeObject<DomainRecordResults>(updateStr);
            }
            catch (Exception ex)
            {
                string message = ex.Message;
            }
            return ret;
        }
    }
}
